import { isString,isNumber,testNumber } from '.'

type DateOpt = Record<string, string>;
// 可自定义组合的时间戳格式化，来自uview-ui的源码
// 改进了两点，1是兼容dateTime为空的情况，2是兼容ios上某些机型不支持yyyy-mm-dd格式的日期格式化，将-替换为/
export type TimeFormat = (dateTime: number | string | Date | null, fmt?: string) => string;
export const timeFormat: TimeFormat = (dateTime = null, fmt = "yyyy/mm/dd") => {
	if (!dateTime) dateTime = new Date().getTime();
	let date:Date
	if (isString(dateTime)&&testNumber(dateTime)) dateTime = Number(dateTime);
	// 如果dateTime长度为10或者13，则为秒和毫秒的时间戳，如果超过13位，则为其他的时间格式
	if (isNumber(dateTime)&&dateTime.toString().length == 10) dateTime *= 1000;
	date = new Date(dateTime);
	if (isString(dateTime)&&!date.getFullYear()) {
		// 有些手机的webview版本过低，没有replaceAll函数
		// 而ios有些又没有replace，需要兼容
		if(dateTime.replaceAll){
			dateTime = dateTime.replaceAll('-','/')
		}else{
			dateTime = dateTime.replace('-\g','/')
		}
		date = new Date(dateTime);
	}
	
	let ret:RegExpExecArray|null;
	const opt: DateOpt = {
		"y+": date.getFullYear().toString(), // 年
		"m+": (date.getMonth() + 1).toString(), // 月
		"d+": date.getDate().toString(), // 日
		"h+": date.getHours().toString(), // 时
		"M+": date.getMinutes().toString(), // 分
		"s+": date.getSeconds().toString(), // 秒
	};
	let k: string;
	for (k in opt) {
		ret = new RegExp(`(${k})`).exec(fmt);
		if (ret) {
			fmt = fmt.replace(
				ret[1],
				ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0")
			);
		}
	}
	return fmt;
};
const numberToInt = (val: number | string) => parseInt(`${val}`);

export type TimeFrom = (dateTime: number | string | Date | null, fmt: string | false) => string;
/**
 * 时间戳转为多久之前，来自uview-ui的源码
 * @param String timestamp 时间戳
 * @param String | Boolean format 如果为时间格式字符串，超出一定时间范围，返回固定的时间格式；
 * 如果为布尔值false，无论什么时间，都返回多久以前的格式
 */
export const timeFrom: TimeFrom = (dateTime = null, format = "yyyy/mm/dd") => {
	if (!dateTime) dateTime = new Date().getTime();
	if (isString(dateTime)&&testNumber(dateTime)) dateTime = Number(dateTime);
	// 如果dateTime长度为10或者13，则为秒和毫秒的时间戳，如果超过13位，则为其他的时间格式
	if (isNumber(dateTime)&&dateTime.toString().length == 10) dateTime *= 1000;
	const timestamp = numberToInt(new Date(dateTime).getTime());
	let timer = new Date().getTime() - timestamp;
	timer = numberToInt(timer / 1000);
	// 如果小于5分钟,则返回"刚刚",其他以此类推
	let tips = "";
	switch (true) {
		case timer < 300:
			tips = "刚刚";
			break;
		case timer >= 300 && timer < 3600:
			tips = `${numberToInt(timer / 60)}分钟前`;
			break;
		case timer >= 3600 && timer < 86400:
			tips = `${numberToInt(timer / 3600)}小时前`;
			break;
		case timer >= 86400 && timer < 2592000:
			tips = `${numberToInt(timer / 86400)}天前`;
			break;
		default:
			// 如果format为false，则无论什么时间戳，都显示xx之前
			if (format === false) {
				if (timer >= 2592000 && timer < 365 * 86400) {
					tips = `${numberToInt(timer / (86400 * 30))}个月前`;
				} else {
					tips = `${numberToInt(timer / (86400 * 365))}年前`;
				}
			} else {
				tips = timeFormat(timestamp, format);
			}
	}
	return tips;
};
// 日期的月或日补零
export const padZero = (value: string | number) => {
	return `00${value}`.slice(-2);
};
export type GetInterval = (timestamp: number) => {
	d: number;
	h: number;
	m: number;
	s: number;
};
/**
 * @description 获取目标时间距离当前时间的时长
 * @param timestamp 13位时间戳
 * @returns {{d:number,h:number,m:number,s:number}} 返回一个包含天、时、分、秒的对象
 */
export const getInterval: GetInterval = (timestamp): { d: number; h: number; m: number; s: number; } => {
	let date = Date.parse(`${new Date()}`) / 1000,
		endTime = timestamp / 1000 - date,
		hour = (endTime / 3600) >> 0,
		h = hour % 24,
		d = (hour - h) / 24,
		min = (endTime - hour * 3600) >> 0,
		m = (min / 60) >> 0,
		s = min - m * 60;
	return {
		d,
		h,
		m,
		s,
	};
};
export type DaysBetweenDates = (dateA: Date, dateB: Date) => number;
/**
 * @description 计算两个日期之间的天数
 * @param dateA Date类型
 * @param dateB
 * @returns {number}
 */
export const daysBetweenDates: DaysBetweenDates = (dateA, dateB): number => {
	const timeDifference = Math.abs(dateA.getTime() - dateB.getTime());
	return Math.floor(timeDifference / (3600 * 24 * 1000));
};
/**
 * @description 获取两个日期之间的日期列表
 * @param dateA Date类型
 * @param dateB
 * @returns {Array<Date>}
 */
export const ListBetweenDates = (dateA: Date, dateB: Date): Array<Date> => {
	const arr: Date[] = [];

	while (dateA <= dateB) {
		arr.push(dateA);
		//获取开始日期时间戳
		let stime = new Date(dateA).getTime();

		//增加一天时间戳后的日期
		let next_date = stime + 24 * 60 * 60 * 1000;

		let y = new Date(next_date).getFullYear() + "/";
		let m =
			new Date(next_date).getMonth() + 1 < 10
				? "0" + (new Date(next_date).getMonth() + 1) + "/"
				: new Date(next_date).getMonth() + 1 + "/";
		let d =
			new Date(next_date).getDate() < 10
				? "0" + new Date(next_date).getDate()
				: new Date(next_date).getDate();

		dateA = new Date(y + m + d);
	}
	return arr;
};

/**
 * @description 获取某个日期前几天或后几天的日期列表
 * @param dateA Date类型
 * @param days 间隔多少天，正数则往后获取，负数则往前获取
 * @param hasToday 返回的数据是否包含传入的日期
 * @returns {Array<Date>}
 */
export const dateBetweenDates = (dateA: Date, days: number, hasToday?: boolean): Array<Date> => {
	const arr: Date[] = [];
	let day = Math.abs(days)
	let multiple = days > 0 ? 1 : -1
	while (0 < day) {

		//获取开始日期时间戳
		let stime = new Date(dateA).getTime();

		//增加一天时间戳后的日期
		let next_date = stime + 24 * 60 * 60 * 1000 * day * multiple;
		arr.push(new Date(next_date));

		day--
	}
	if (hasToday) {
		arr.push(dateA)
	}
	if (days > 0) {
		arr.reverse()
	}
	return arr;
};

/**
 * @description 获取某个日期对应月份的第一天0时0分，不传参数则获取当前日期
 * @param date string|number
 * @returns {number}
 */
export const getMonthStartTime = (date?: string | number): number => {
	let _date = date ? new Date(date) : new Date()
	_date.setDate(1)
	return _date.getTime()
}
/**
 * @description 获取某个日期对应月份的最后一天23时59分59秒，不传参数则获取当前日期
 * @param date string|number
 * @returns {number}
 */
export const getMonthEndTime = (date?: string | number): number => {
	let _date = date ? new Date(date) : new Date()
	let year = _date.getFullYear()
	let month = _date.getMonth() + 1
	let nextMonthFirthDay = new Date(year, month, 1).getTime() // 下个月的第一天
	let oneDay = 1000 * 60 * 60 * 24 // 
	let endDay = new Date(nextMonthFirthDay - oneDay)
	let day = endDay.getDate() // 本月最后一天
	return new Date(`${year}/${month}/${day} 23:59:59`).getTime()
}

/**
 * @description 获取某个日期的0时0分，不传参数则获取当前日期
 * @param date string|number
 * @returns {number}
 */
export const getDayStartTime = (date?: string | number): number => {
	let _date = date ? new Date(date) : new Date()
	return new Date(_date.toLocaleDateString()).getTime()
}

/**
 * @description 获取某个日期的23时59分59秒，不传参数则获取当前日期
 * @param date string|number
 * @returns {number}
 */
export const getDayEndTime = (date?: string | number): number => {
	let _date = date ? new Date(date) : new Date()
	return new Date(`${_date.toLocaleDateString()} 23:59:59`).getTime()
}


